home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / clipper / ks94an.zip / IMPORTP.HDR < prev    next >
Text File  |  1994-04-25  |  14KB  |  399 lines

  1. /******************************************************************************
  2.                  The Klipper Library, for CA-Clipper 5.x
  3.         Copyright (c), 1994, Wallace Information Systems Engineering
  4.  
  5. FUNCTION:
  6.  
  7. _ImportP(cDefFileName,cImpFileName,cCommentChar,cDataChar) --> nNumLinesRead
  8.  
  9. PARAMETERS:
  10.  
  11. cDefFileName : Import Definition File
  12. cImpFileName : Import Data File
  13. cCommentChar : Text to denote comment line (Default NONE)
  14. cDataChar    : Text to denote valid data line (Default NONE)
  15.  
  16. SHORT:
  17.  
  18. Formatted import from text file.
  19.  
  20. DESCRIPTION:
  21.  
  22. CAUTION: _ImportP() can be a very complex function to understand and
  23. implement.  In the long run, the time you spend learning how to use it will
  24. benefit you.
  25.  
  26. The inspiration for this funtion came from an application that I once wrote
  27. that had to import data from a mainframe text file each month. But,
  28. unfortunately, the format of the text file changed frequently.
  29.  
  30. For those of you who have ever worked in a "test/production WITH change
  31. control" environment, you know that simply changing the program and
  32. recompiling won't work efficiently or quickly.  You have to be given access
  33. to the program's source code, set up a test environment, make changes, test,
  34. call change control to move the application to the production environment
  35. (which you don't have access to), and resubmit the source code to production
  36. control. All in all, it is VERY time consuming.
  37.  
  38. But what if the application could "interpret" the import file by means of a
  39. file layout or definition in another file?  Then, the import routine could be
  40. changed without ANY source code changes to the application.
  41.  
  42. Why, then you would have something like _ImportP()!
  43.  
  44. _ImportP() (Import Positional), is a general purpose importing mechanism that
  45. imports an ASCII text file into a database according to a definition laid out
  46. in another text data file..
  47.  
  48. The receiving database must be open, with any indexes, in the current area.
  49. Records are APPENDED to the database.
  50.  
  51. The Import Data File must be a plain ASCII file.
  52.  
  53.  
  54. Sample function call: _ImportP(IMPORT.DFN,IMPORT.TXT, '//')
  55.  
  56. The Definition File must describe the contents of the import data file and
  57. the fields into which each piece of data is to be placed in the following
  58. manner:
  59.  
  60.     <top of file>
  61.     //
  62.     // Import Definition File for Quarterly Budget Mainframe Import
  63.     // Contact XYZ Corp. Operations Services for Support
  64.     //
  65.     // STRUCTURE OF DEFINITION TEXT FILE: IMPORT.TXT
  66.     // TARGET DATABASE: BUDGET.DBF
  67.     // -----------------------------------------------------
  68.  
  69.     LINEPROC: ShowCount(nLineNum)
  70.  
  71.     POSITION:1/16  FIELD:Name
  72.     POSITION:17/9  FIELD:SSN
  73.     POSITION:26/8  FIELD:INTEGER
  74.     POSITION:34/9  FIELD:DECIMAL1 TYPE:1
  75.     POSITION:43/11 FIELD:DECIMAL2 TYPE:3
  76.     POSITION:54/6  FIELD:DATE1    TYPE:1
  77.     POSITION:60/8  FIELD:DATE2    TYPE:1
  78.     POSITION:68/8  FIELD:DATE3    TYPE:3
  79.     <end of file>
  80.  
  81. *** LINEPROC DISCUSSION ***
  82.  
  83. LINEPROC: denotes the name of a function that is executed after each line of
  84. the import file is read.  This provides an opportunity to, for example, make
  85. a "status" screen indicating progress.  The only "exported" data from the
  86. function is the current line count of the import file.  This counter is
  87. updated in a variable that the calling application provides by name as the
  88. parameter to the LINEPROC function.  (In the above example, the application
  89. that calls the _ImportP() function must have a function called SHOWCOUNT() in
  90. scope at the time the import begins.  Additionally, the function call
  91. indicates that the memory variable to receive the current line count is
  92. "nLineNum".  It must be of type numeric and must be in scope at the time the
  93. import begins.)
  94.  
  95. Here is the logic behind it:  When the _ImportP() function is called, it runs
  96. until completion before returning to the calling application.  What this
  97. means is that there is no return value until the import is completely done.
  98. In order to give the application any clue as to what is happening inside the
  99. function (and thereby give the user any indication), it must declare a public
  100. or private memvar to hold a line count (the only data "exported" by the
  101. function during execution) and tell the _ImportP() function to update it with
  102. the current number of lines read as it progresses.
  103.  
  104. Furthermore, the calling application must specify a function that is to be
  105. called by _ImportP() as each line is read.  This function is written and
  106. linked into the application and then the application must tell the _ImportP()
  107. function to call that function after each line of import text has been read.
  108.  
  109. The name of this function, AND the name of the variable that has been setup
  110. for it's use are BOTH defined on the LINEPROC line.  Since the function only
  111. exports the current line number, then only one variable can be used in the
  112. LINEPROC function.
  113.  
  114. If the Import Definition File contains: "LINEPROC:ShowCount(a,b,c)" you will
  115. have trouble when the _ImportP() function tries to interpret "a,b,c" as the
  116. name of a numeric variable to increment.
  117.  
  118. The correct implementation is:
  119.  
  120. LINEPROC:YourFunctionName(YourNumericVariableName)
  121.  
  122. The result will be: YourFunctionName() will be called for each import data
  123. file line read, and the counter variable YourNumericVariableName will be
  124. incremented.
  125.  
  126. Here's the implementation:
  127.  
  128.     // in the calling APP
  129.     PRIVATE nCounter := 0
  130.  
  131.     // also in the calling APP
  132.     FUNCTION ShowCount()
  133.     MEMVAR nCounter
  134.  
  135.     @ 01,01 say 'Record Counter: '+ltrim(str(nCounter))
  136.  
  137.     RETURN(NIL)
  138.  
  139.     // in the definition file
  140.     LINEPROC:ShowCount(nCounter)
  141.  
  142.     _ImportP(...)
  143.  
  144. When the definition file is read, the line that defines the LINEPROC
  145. funciton:
  146.  
  147. 1. Names the function to call: ShowCount()
  148.  
  149. 2. Determines the name of the variable that will receive the line counter.
  150.  
  151. Obviously if this variable is not in scope at this time, you will get a
  152. run-time error in the usual way:
  153.  
  154. "Variable does not exist: nCounter"
  155.  
  156. *** POSITION, FIELD, TYPE DISCUSSION ***
  157.  
  158. POSITION: denotes the starting position and length of the field in the import
  159. data file.  The import definition file must not necessarily define the entire
  160. file.  You may include POSITION: labels for only that data which is needed
  161. and the undefined portion of the line will be ignored.
  162.  
  163. FIELD: denotes the a field name to receive the data.  This field must be
  164. present in the current database work area. Legally, this database need not be
  165. open for EXCLUSIVE access, but it is recommended that it be open EXCLUSIVELY
  166. since if the import fails for any reason, all records added since the import
  167. began are deleted, which might also include records appended by other
  168. applications.
  169.  
  170. TYPE: denotes the data format of the import data.
  171.  
  172. Keep in mind that in an ASCII file, ALL data is character.  In order to
  173. convert it to other data types during import, you will need to tell the
  174. function something about the type of data it is getting and how to interpret
  175. it.  For instance, many mainframe text files use packed decimal or, more
  176. commonly, "implied" decimal places in numerics.  So, for example, the string
  177. of digits "1234" might mean 1234, 123.4, 12.34, 1.234, or .1234.  When
  178. _ImportP() comes across this, how do you tell it how to convert it?  With the
  179. TYPE: token.
  180.  
  181. For numerics data, it specifies the number of decimal places to insert. If
  182. not specified at all, no decimal places are assumed.
  183.  
  184. TEXT        TYPE           RESULT
  185. -------------------------------------
  186. "12345678"  TYPE:2  -->    123456.78
  187. "12345678"  TYPE:3  -->    12345.678
  188. "12345678"  <none>  -->     12345678
  189.  
  190.  
  191. NOTE:
  192.  
  193. TYPE: does not determine the data type that the import data will be converted
  194. to - that information is derived from the database field specified in the
  195. FIELD token.  It only specifies the FORMAT of the data, ie the numeric "type"
  196. or the date "type."
  197.  
  198. If decimals are present in the import file, ie, "123.4" then IMPLICIT
  199. DECIMALS are used no matter what the TYPE token specifies.
  200.  
  201. If TYPE: is not specified, the data format defaults to NO DECIMALS
  202. UNLESS IMPLICIT for numerics and MM/DD/YY for date types.
  203.  
  204. For all types other than NUMERIC and DATE, the TYPE token has no meaning and
  205. will be ignored if specified.
  206.  
  207. If you are not interested in certain characters from the import file,
  208. then simply omit describing them in the Import Definition File and they
  209. will not be read.
  210.  
  211. Note that there can be NO SPACES between the colon of each token and
  212. it's coresponding value.  "TYPE:1" is OK, but "TYPE: 1", "TYPE : 1", and
  213. "TYPE : 1" are all out.
  214.  
  215. FIELD:NAME              is OK
  216. FIELD: Name             is NOT OK
  217.  
  218. *** NUMERIC TYPE SPECIFIERS ***
  219.  
  220. Example - TYPE:n, where n = Implied Decimals places
  221.  
  222. If you specify an implied decimal places and an exlicit decimal is found,
  223. then _ImportP() will automatically switch to implicit decimals mode for
  224. that field.  Implicit decimals means that the decimal point is present in
  225. the data file.  If no decimal point is present, yet the numbers are
  226. decimal numbers, use a TYPE:n to define the number of implied decimal
  227. places to assume.
  228.  
  229. *** DATE TYPE SPECIFIERS ***
  230.  
  231. Example - TYPE:n
  232.  
  233. Where n = 1  MM/DD/YY or MMDDYY       Standard
  234.           2  DD/MM/YY or DDMMYY       English
  235.           3  MM/DD/YYYY or MMDDYYYY   Standard, 4 digit year
  236.           4  DD/MM/YYYY or DDMMYYYY   English,  4 digit year
  237.           5  DDDYY                    Julian 2 digit year
  238.           6  DDDYYYY                  Julian 4 digit year
  239.  
  240.  
  241. Note that type 1, for example, considers MM/DD/YY and MMDDYY the same.  This
  242. is because all "/"'s are stripped from the data before an attempt is made to
  243. interpret the date.
  244.  
  245. If the cCommentChar is specified, the same comment character(s) must be
  246. used in both the import file and the definition file! Use caution
  247. when specifing the cCommentChar so that you do not use any character
  248. sequence that might be actual data in the import file!
  249.  
  250. *** LOGICAL TYPES ***
  251.  
  252. There is no TYPE token for Logical Field values.  If the import database
  253. field determines that the incoming data should be a logical, then logical
  254. values are assumed according to the following table:
  255.  
  256.     TRUE         FALSE
  257.     --------------------
  258.     "Y"         "N"
  259.     "y"         "n"
  260.     "T"         "F"
  261.     "t"         "f"
  262.     "1"         "0"
  263.     "TRUE"      "FALSE"
  264.  
  265. Any other character(s) found in the import file that are being placed into
  266. a logical field will cause the import to fail.
  267.  
  268. WHEN AN IMPORT FAILS
  269.  
  270. An import can be caused to fail by any of a number of conditions, all but
  271. one of which are related to data that is incompatible with the field that has
  272. been specified *with* the TYPE: format that has been specified.
  273.  
  274. The following are these causes.  The FIRST one is the only non-data related
  275. way of failing an import.
  276.  
  277. 1 - User Presses ESC during import.
  278.  
  279. 2 - Integer portion of numeric data exceeds capacity of the specified
  280. field (ie, Data Width Error)
  281.  
  282. 3 - Decimal portion (whether explicit or implied) exceeds capacity
  283. of specified field.  No rounding takes place.  If you specify three
  284. decimal places and the field contains only two decimal places, it's over.
  285. (ie, Data Width Error)
  286.  
  287. 4 - Date does not match the format you specified in the Import
  288. Definition File.  If you specify TYPE:6 (DDDYY) and the file actually
  289. contains MM/DD/YY.  It is immediatly over since you will be one digit short
  290. of a full date (DDDYY has five, MM/DD/YY has six).  Other times may be
  291. more tricky.  If you specify the Standard date format and then actually get
  292. an English date in the import file, you may or may not make it though.
  293. Either way, unless the Month and Day are exactly the same, you are going
  294. to end up with the wrong date my a margin of several months.
  295.  
  296. 5 - Something other than Y,y,N,n,T,t,F,f,1,0,TRUE,FALSE shows up in
  297. a POSITION: range that is mapped to a logical field.
  298.  
  299.  
  300. When an import fails, all records added to the database since the import
  301. began are marked for deletion and a return code is set.
  302.  
  303. *** RETURN CODES ***
  304.  
  305. The return code is a decimal number.  The integer portion indicates the
  306. error number and the decimal portion indicates the line number of either
  307. the import definition file or the import data file where the error occured.
  308.  
  309. #      Meaning
  310. ------------------------------------------------------------------
  311.  
  312. 0 No error - Import completed.
  313.  
  314. 1 This line of the import definition was missing a required POSITION: label.
  315.  
  316. 2 This line of the import definition was missing a required FIELD: label.
  317.  
  318. 3 This line of the Import Definition specified a field name that does
  319. not exist in the database.
  320.  
  321. 4 Explicit Decimals in data file exceed capacity of the specified
  322. database field.
  323.  
  324.  
  325. 5 Integer places exceed field capacity in non-int number
  326.  
  327. 6 Integer places exceed field capacity in integer number
  328.  
  329. 7 Invalid data in LOGICAL field
  330.  
  331. 8 Character data in import file exceeded capacity of specified database
  332. field.
  333.  
  334. 9 Botched Function call in LINEPROC:
  335.  
  336. 10 No database was open when the import was attempted.
  337.  
  338. EXAMPLE:
  339.  
  340. FUNCTION Main()
  341. #include "kfile.ch"
  342.  
  343. MEMVAR  nCounter
  344. PRIVATE nCounter := 0
  345.  
  346. FILE_BEGIN TEST.DBF
  347.  
  348.     FLD Name,     C, 16
  349.     FLD SSN,      C,  9
  350.     FLD INTEGER,  N,  8
  351.     FLD DECIMAL1, N, 10, 1
  352.     FLD DECIMAL2, N, 10, 1
  353.     FLD DECIMAL3, N, 12, 3
  354.     FLD DATE1,    D
  355.     FLD DATE2,    D
  356.     FLD DATE3,    D
  357.     FLD DATE4,    D
  358.     FLD DATE5,    D
  359.     FLD DATE6,    D
  360.     FLD DATE7,    D
  361.     FLD Memo,     M
  362.     FLD Log1,     L
  363.     FLD Log2,     L
  364.     FLD Log3,     L
  365.  
  366. FILE_END TEST.DBF
  367.  
  368. FILE_BEGIN TEST2.DBF
  369.  
  370.     FLD NUMBER,   C, 7
  371.     FLD DATE1,    D
  372.     FLD DATE2,    D
  373.     FLD DATE3,    D
  374.     FLD DATE4,    D
  375.     FLD DATE5,    D
  376.     FLD DATE6,    D
  377.     FLD DATE7,    D
  378.     FLD DATE8,    D
  379.     FLD DATE9,    D
  380.  
  381. FILE_END TEST2.DBF
  382.  
  383. USE TEST.DBF ALIAS test
  384. ZAP
  385.  
  386. INDEX ON test->name TO test
  387.  
  388. CLEAR SCREEN
  389.  
  390. ?
  391. ? 'Return: '+str(_ImportP('test.def','test.txt','//'))
  392.  
  393. RETURN(NIL)
  394.  
  395. SEE DEMO\IMPORTP\IMPTEXT.PRG for a working example with data and definition
  396. files.
  397.  
  398. ******************************************************************************/
  399.